package com.lianmai.chaincard.utils;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.List;

/**
 * 文件相关
 */
public class FileUtil {

    /**
     * 文件是否存在
     *
     * @param filePath 文件路径
     * @return true 文件存在
     */
    public static boolean isExist(String filePath) {
        return filePath != null && new File(filePath).exists();
    }

    /**
     * 删除文件
     *
     * @param file 文件对象
     * @param r    是否递归删除目录
     */
    public static void deleteFile(File file, boolean r) {
        if (file == null) {
            return;
        }
        if (file.isFile()) {
            file.delete();
        } else {
            if (r) {
                File[] files = file.listFiles();
                if (files != null) {
                    for (int i = 0; i < files.length; i++) {
                        deleteFile(files[i], r);
                    }
                }
                file.delete();
            }
        }
    }

    /**
     * 删除文件
     *
     * @param absolutePath 要删除的文件绝对路径
     * @param r            是否递归删除目录
     */
    public static void deleteFile(String absolutePath, boolean r) {
        File file = new File(absolutePath);
        if (file.isFile()) {
            file.delete();
        } else {
            if (r) {
                File[] files = file.listFiles();
                if (files != null) {
                    for (int i = 0; i < files.length; i++) {
                        deleteFile(files[i], r);
                    }
                }
                file.delete();
            }
        }
    }

    /**
     * 写文本数据
     *
     * @param absolutePath 写入绝对路径
     * @param content      文本字符串
     * @return 操作是否成功
     */
    public static boolean writeFile(String absolutePath, String content) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(absolutePath);
            byte[] byteContent = content.getBytes();
            fos.write(byteContent);
            fos.flush();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) fos.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        return false;
    }

    public static boolean writeFile(InputStream inputStream, String destFilePath) {
        if (inputStream == null) {
            return false;
        }
        FileOutputStream fos = null;
        try {
            File dst = new File(destFilePath);
            if (!dst.getParentFile().exists() && !dst.getParentFile().mkdirs()) {
                return false;
            }
            fos = new FileOutputStream(destFilePath);
            byte[] byteContent = new byte[1024];
            int count;
            while ((count = inputStream.read(byteContent)) != -1) {
                fos.write(byteContent, 0, count);
            }
            fos.flush();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) fos.close();
                inputStream.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 读取文本文件
     *
     * @param absolutePath 文件绝对路径
     * @return 文本数据
     */
    public static String readFile(String absolutePath) {
        if (absolutePath == null || !new File(absolutePath).exists()) {
            return null;
        }
        FileInputStream fis = null;
        String content = null;
        try {
            fis = new FileInputStream(absolutePath);
            byte[] buffer = new byte[1024];
            ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
            while (true) {
                int readLength = fis.read(buffer);
                if (readLength == -1) break;
                arrayOutputStream.write(buffer, 0, readLength);
            }
            fis.close();
            arrayOutputStream.close();
            content = new String(arrayOutputStream.toByteArray());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            content = null;
        } finally {
            try {
                if (fis != null) fis.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        return content;
    }


    /**
     * 存储单个Parcelable对象
     *
     * @param context      程序上下文
     * @param fileName     文件名，要在系统内保持唯一
     * @param parcelObject 对象必须实现Parcelable
     * @return boolean 存储成功的标志
     */
    public static boolean writeParcelable(Context context, String fileName, Parcelable parcelObject) {
        boolean success = false;
        FileOutputStream fos = null;
        try {
            fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
            Parcel parcel = Parcel.obtain();
            parcel.writeParcelable(parcelObject, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
            byte[] data = parcel.marshall();
            parcel.recycle();
            fos.write(data);
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }

        return success;
    }

    /**
     * 存储List对象
     *
     * @param context  程序上下文
     * @param fileName 文件名，要在系统内保持唯一
     * @param list     对象数组集合，对象必须实现Parcelable
     * @return boolean 存储成功的标志
     */
    public static boolean writeParcelableList(Context context, String fileName, List<Parcelable> list) {
        boolean success = false;
        FileOutputStream fos = null;
        try {
            if (list != null) {
                fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
                Parcel parcel = Parcel.obtain();
                parcel.writeList(list);
                byte[] data = parcel.marshall();
                fos.write(data);

                success = true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }

        return success;
    }

    /**
     * 读取单个数据对象
     *
     * @param context  程序上下文
     * @param fileName 文件名
     * @return Parcelable, 读取到的Parcelable对象，失败返回null
     */
    @SuppressWarnings("unchecked")
    public static Parcelable readParcelable(Context context, String fileName, ClassLoader classLoader) {
        Parcelable parcelable = null;
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            fis = context.openFileInput(fileName);
            if (fis != null) {
                bos = new ByteArrayOutputStream();
                byte[] b = new byte[4096];
                int bytesRead;
                while ((bytesRead = fis.read(b)) != -1) {
                    bos.write(b, 0, bytesRead);
                }

                byte[] data = bos.toByteArray();

                Parcel parcel = Parcel.obtain();
                parcel.unmarshall(data, 0, data.length);
                parcel.setDataPosition(0);
                parcelable = parcel.readParcelable(classLoader);
                parcel.recycle();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            parcelable = null;
        } finally {
            if (fis != null) try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (bos != null) try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return parcelable;
    }

    /**
     * 读取数据对象列表
     *
     * @param context  程序上下文
     * @param fileName 文件名
     * @return List, 读取到的对象数组，失败返回null
     */
    @SuppressWarnings("unchecked")
    public static List<Parcelable> readParcelableList(Context context, String fileName, ClassLoader classLoader) {
        List<Parcelable> results = null;
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            fis = context.openFileInput(fileName);
            if (fis != null) {
                bos = new ByteArrayOutputStream();
                byte[] b = new byte[4096];
                int bytesRead;
                while ((bytesRead = fis.read(b)) != -1) {
                    bos.write(b, 0, bytesRead);
                }

                byte[] data = bos.toByteArray();

                Parcel parcel = Parcel.obtain();
                parcel.unmarshall(data, 0, data.length);
                parcel.setDataPosition(0);
                results = parcel.readArrayList(classLoader);
                parcel.recycle();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            results = null;
        } finally {
            if (fis != null) try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (bos != null) try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return results;
    }

    public static boolean saveSerializable(OutputStream os, Serializable data) {
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(os);
            oos.writeObject(data);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public static Serializable readSerializable(InputStream is) {
        Serializable data = null;
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(is);
            data = (Serializable) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return data;
    }

    /**
     * 读取assets目录下文本文件
     *
     * @param context  Context
     * @param fileName 文件名
     * @return 文本数据
     */
    public static String readAssets(Context context, String fileName) {
        BufferedReader bufReader = null;
        try {
            InputStreamReader inputReader = new InputStreamReader(context.getResources().getAssets().open(fileName));
            bufReader = new BufferedReader(inputReader);
            String line;
            String Result = "";
            while ((line = bufReader.readLine()) != null)
                Result += line;
            return Result;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufReader != null) {
                try {
                    bufReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 复制文件
     *
     * @param srcFile 源文件路径
     * @param dstFile 目标文件路径
     * @return 操作是否成功
     */
    public static boolean copy(String srcFile, String dstFile) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {

            File dst = new File(dstFile);
            if (!dst.getParentFile().exists() && !dst.getParentFile().mkdirs()) {
                return false;
            }

            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(dstFile);

            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return false;
    }

    /**
     * 获取指定文件大小
     *
     * @param file File
     * @return size
     */
    public static long getFileSize(File file) {
        if (file == null || !file.exists()) {
            return 0;
        }
        long s = 0;
        if (file.isFile()) {
            s = file.length();
        } else {
            File[] files = file.listFiles();
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    s += getFileSize(files[i]);
                }
            }
        }
        return s;
    }

    public static String getFileSizeWithUnit(float size) {
        if (size > 1024 * 1024) {
            return String.format("%.2fMB", size / 1024 / 1024);
        } else if (size > 1024) {
            return String.format("%.2fKB", size / 1024);
        } else {
            return String.format("%.2fB", size);
        }
    }

    /**
     * 判断文件的编码格式
     *
     * @param filePath 文件路径
     * @return 文件编码格式
     */
    public static String getCharsetName(String filePath) {
        BufferedInputStream bin = null;
        String charsetName = "GBK";
        try {
            bin = new BufferedInputStream(new FileInputStream(filePath));
            bin.mark(4);
            byte[] first3Bytes = new byte[3];
            int read = bin.read(first3Bytes, 0, 3);
            if (read == -1)
                return charsetName;
            if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
                return "UTF-16LE";
            } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
                return "UTF-16BE";
            } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {
                return "UTF-8";
            }
            bin.reset();
            while ((read = bin.read()) != -1) {
                if (read >= 0xF0)
                    break;
                //单独出现BF以下的，也算是GBK
                if (0x80 <= read && read <= 0xBF)
                    break;
                if (0xC0 <= read && read <= 0xDF) {
                    read = bin.read();
                    if (0x80 <= read && read <= 0xBF)// 双字节 (0xC0 - 0xDF)
                        // (0x80 - 0xBF),也可能在GB编码内
                        continue;
                    else
                        break;
                    // 也有可能出错，但是几率较小
                } else if (0xE0 <= read && read <= 0xEF) {
                    read = bin.read();
                    if (0x80 <= read && read <= 0xBF) {
                        read = bin.read();
                        if (0x80 <= read && read <= 0xBF) {
                            charsetName = "UTF-8";
                            break;
                        } else
                            break;
                    } else
                        break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bin != null) {
                try {
                    bin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return charsetName;
    }
}
